from flask import Flask, jsonify, request, make_response, session, redirect, url_for
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import SingletonThreadPool
from sql import User, Driver, Order
import functools
import requests

app = Flask(__name__,
            static_folder='static',
            static_url_path='/static',
            template_folder='templates')
app.config['SECRET_KEY'] = '234324hjsfsdf%^%&%&^@#'
# 初始化数据库连接:
engine = create_engine('sqlite:///data.db',
                       poolclass=SingletonThreadPool,
                       connect_args={'check_same_thread': False},
                       echo=False)
# 创建DBSession类型:
DBSession = sessionmaker(bind=engine)
conn = DBSession()


def authorized(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            token = session.get(text)
            if token:
                return func(*args, **kw)
            else:
                return make_response('you don\'t have the permission.')

        return wrapper

    return decorator


def get_all(req: request, *args):
    l = []
    if req.method == 'GET':
        for arg in args:
            l.append(req.args.get(arg, None))
    elif req.method == 'POST':
        for arg in args:
            l.append(req.form.get(arg, None))
    return tuple(l)


def check(*args):
    for arg in args:
        if arg is None:
            return False
        else:
            print(arg)
    return True

def get_distance(srcLon, srcLat, dstLon, dstLat):
    url = 'https://restapi.amap.com/v3/direction/driving?parameters'
    key = '2e61438040b538cdef1e412bc917a2e8'
    origin = str(srcLon) + ',' + str(srcLat)
    destination = str(dstLon) + ',' + str(dstLat)
    params = {
        'key': key,
        'origin': origin,
        'destination': destination,
        'extensions': 'all',
        'output': 'JSON'
    }
    response = requests.get(url,params=params)
    result = response.json()
    if not result.get('route',None):
        return None
    return result

@app.route('/', methods=['GET'])
def index():
    return jsonify({'body': 'Hello'})


@app.route('/register/user', methods=['GET', 'POST'])
def register_user():
    name, account, passwd = get_all(request, 'name', 'account', 'password')
    if not check(name, account, passwd):
        return make_response('miss some parameter')
    user = conn.query(User).filter(User.account == account).filter(
        User.password == passwd).one_or_none()
    if user is None:
        conn.add(
            User(account=account,
                 name=name,
                 password=passwd,
                 balance=50.0,
                 status=0))
        conn.commit()
        return jsonify({'status': "succeed"})
    else:
        conn.commit()
        return jsonify({'status': "failed"})


@app.route('/register/driver', methods=['POST', 'GET'])
def register_driver():
    if request.method == 'GET':
        return redirect('../static/register_driver.html')
    account, name, password, carType, carCode = get_all(
        request, 'account', 'name', 'password', 'cartype', 'carcode')
    if not check(account, name, password, carType, carCode):
        return make_response('miss some parameter')
    driver = conn.query(Driver).filter(Driver.account == account).filter(
        Driver.password == password).one_or_none()
    if driver is None:
        conn.add(
            Driver(name=name,
                   account=account,
                   password=password,
                   balance=10,
                   carType=carType,
                   carCode=carCode))
        conn.commit()
        return jsonify({'status': "succeed"})
    else:
        conn.commit()
        return jsonify({'status': "failed"})


@app.route('/signin/<usertype>', methods=['GET', 'POST'])
def signin(usertype):
    account, password = get_all(request, 'account', 'password')
    check(account, password)
    if usertype == 'user':
        user = conn.query(User).filter(User.account == account).filter(
            User.password == password).one_or_none()
        if user is not None:
            conn.query(User).filter_by(id=user.id).update({'status': 1})
            conn.commit()
            print('*********id', user.id)
            return jsonify({
                'status': 'online',
                'id': user.id,
                'name': user.name,
                'balance': user.balance
            })
        else:
            conn.commit()
            print({'status': 'failed', "errorcode": 1006,"error":"no such user"})
            return jsonify({'status': 'failed', "errorcode": 1006,"error":"no such user"})
    elif usertype == 'driver':
        driver = conn.query(Driver).filter(
            Driver.account == account
            and Driver.password == password).one_or_none()
        if driver is not None:
            conn.query(Driver).filter_by(id=driver.id).update({'status': 1})
            conn.commit()
            return jsonify({
                'status': 'online',
                'id': driver.id,
                'name': driver.name,
                'balance': driver.balance,
                'carType': driver.carType,
                'carCode': driver.carCode
            })
        else:
            conn.commit()
            return jsonify({'status': 'failed',"errorcode": "1007","error": "account or password input error"})


@app.route('/logout/<usertype>', methods=['GET', 'POST'])
def logout(usertype):
    uid = get_all(request, 'uid')
    check(uid)
    if usertype == 'user':
        conn.query(User).filter(User.id == uid[0]).update({'status': 0})
    else:
        conn.query(Driver).filter(Driver.id == uid[0]).update({'status': 0})
    conn.commit()
    return jsonify({"status":"succeed"})


@app.route('/preorder', methods=['GET', 'POST'])
# @authorized('uid')
def pre_list():
    l = get_all(request, 'sourceName','sourceLatitude', 'sourceLongitude', 'destName', 'destLatitude', 'destLongitude', 'startTime', 'uid')
    if not check(*l):
        return make_response('miss some parameters')
    order = Order(uid=l[7],
                  sourceName=l[0],
                  sourceLatitude=l[1],
                  sourceLongitude=l[2],
                  destName=l[3],
                  destLatitude=l[4],
                  destLongitude=l[5],
                  start_time=l[6],
                  status=0)
    conn.add(order)
    conn.commit()
    return jsonify({'orderId': order.id})

'''
@app.route('/avalOrder', methods=['GET', 'POST'])
# @authorized('uid')
def avaliable_order():
    orders = conn.query(Order).filter(Order.status == 0).all()
    conn.commit()
    d = dict()
    for order in orders:
        d[str(order.id)] = order.to_dict()
    return jsonify(d)
'''

@app.route('/acceptOrder', methods=['GET', 'POST'])
def accept_order():

    uid, longitude, latitude = get_all(request, 'uid', 'longitude', 'latitude')
    if not check(uid, longitude, latitude):
        return make_response('miss some parameter')

    reqList =conn.query(Order).filter(Order.status == 0).all()
    if not reqList:
        print("*******error1001")
        return jsonify({"status": "failed","errorcode": 1001, "error":"no order to be accepted, please wait passenger to make an order request"})
    disList = []
    for req in reqList:
        passenger = conn.query(User).filter(User.id == req.uid).one_or_none()
        if not passenger:
            print("******error1002")
            return jsonify({"status": "failed","errorcode": 1002, "error":"no such user"})
        clientPath = get_distance(longitude, latitude, req.sourceLongitude, req.sourceLatitude)
        destPath = get_distance(req.sourceLongitude,req.sourceLatitude, req.destLongitude, req.destLatitude)
        if not check(clientPath, destPath):
            return jsonify({"status": "failed"})
        disList.append({'name': passenger.name,
                        'phone': passenger.account,
                        'order_id': req.id,
                        'client_place': req.sourceName,
                        'place': req.destName,
                        'price': float(clientPath['route']['taxi_cost']),
                        'distance_client': int(clientPath['route']['paths'][0]['distance']),
                        'distance': int(destPath['route']['paths'][0]['distance'])
                        })
    res = sorted(disList, key=lambda x: x['distance_client'])
    #######logging
    print("********logging*********")
    print({'result': res,'status': 'succeed'})
    ######logging
    return jsonify({'result': res,'status': 'succeed'})


@app.route('/takeOrder/<int:oid>', methods=['GET', 'POST'])
# @authorized('uid')
def take_order(oid):
    did, longitude, latitude = get_all(request, 'uid', 'longitude', 'latitude')
    check(did, longitude, latitude)
    order = conn.query(Order).filter(Order.id == oid).one_or_none()
    conn.query(Order).filter(Order.id == oid).update({
        'did': did,
        'driverLongitude': longitude,
        'driverLatitude': latitude,
        'status': 1
    })
    conn.commit()
    return jsonify(order.to_dict())

@app.route('/orderStatus/<int:oid>', methods=['GET', 'POST'])
def order_status(oid):
    order = conn.query(Order).filter(Order.id == oid).one_or_none()
    if not order:
        return jsonify({"status":"failed","errorcode":"1003","error":"no such order"})
    driver = conn.query(Driver).filter(Driver.id == order.did).one_or_none()
    if not driver:
        return jsonify({"status":"failed","errorcode":"1005","error":"no such driver"})
    passenger = conn.query(User).filter(User.id == order.uid).one_or_none()
    if order.status == 0:
        return jsonify({"status":"waiting"})
    elif order.status == 1:
        res = { "driver_name": driver.name,
                "car_code": driver.carCode,
                "car_type": driver.carType,
                "passenger_name": passenger.name,
                "type": False,
                "finished": True,
                "start_place": order.sourceName,
                "end_place": order.destName,
                "cost": get_distance(order.sourceLongitude,order.sourceLatitude, order.destLongitude, order.destLatitude)['route']['taxi_cost']
              }
        return jsonify({"status":"succeed","result":res})
    else:
        return jsonify({"status":"failed","errorcode":"1004","error":"order outdated"})

@app.route('/run/<int:oid>', methods=['GET', 'POST'])
# @authorized('uid')
def run_order(oid):
    order = conn.query(Order).filter(Order.id == oid).one_or_none()
    if order is not None:
        conn.query(Order).filter(Order.id == oid).update({'status': 2})
        conn.commit()
        return jsonify(order.to_dict())
    else:
        return jsonify(order.to_dict())


@app.route('/finish/<int:oid>', methods=['GET', 'POST'])
# @authorized('uid')
def finish(oid):
    order = conn.query(Order).filter(Order.id == oid).one_or_none()
    if order is not None:
        conn.query(Order).filter(Order.id == oid).update({'status': 3})
        conn.commit()
        return jsonify(order.to_dict())
    else:
        return jsonify(order.to_dict())


'''
@app.route('/cancel/driver/<int:oid>', methods=['GET', 'POST'])
@authorized('uid')
def cancel_by_driver(oid):
    id = session.get('uid')
    order = conn.query(Order).filter(Order.id == oid).filter(
        Order.did == id).one_or_one()
    if order is not None:
        conn.query(Order).filter(Order.id == oid).filter(
            Order.did == id).update({'status': 4})
        conn.commit()
        return jsonify({'status': 'succeed'})
    else:
        return jsonify({'status': 'failed'})
'''


@app.route('/order/<int:oid>', methods=['GET', 'POST'])
# @authorized('uid')
def listener_for_user(oid):
    if oid <= 0:
        return make_response('the id is invalid.')
    order = conn.query(Order).filter(Order.id == oid).one_or_none()
    if order is not None:
        return jsonify(order.to_dict())
    else:
        return make_response('the id is invalid.')


if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=5000)
